package socketinterface;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import com.vast.ui.component.commands.LedUpdate;
import com.vast.ui.component.commands.MacroCommand;
import com.vast.ui.component.models.Led;
import com.vast.ui.ledpanel.views.ViewPart;

public class ServerController implements Runnable, ServerInterface{
	public  ViewPart     view;
	private int          serverPort   = 20000;
	private ServerSocket serverSocket = null;
	private Socket clientSocket = null;
	private Logger       logger;
	private DataInputStream   in = null;
	private DataOutputStream  out = null;
	private boolean isThreadRunning = false;
	private boolean isServerRunning = false;
	public  MacroCommand commandList;
	
	public synchronized boolean getIsThreadRuning() {
		return isThreadRunning;
	}
	
	public synchronized void putIsThreadRuning(boolean state) {
		isThreadRunning = state;
	}
	
	public ServerController(ViewPart view){
		this.view = view;
		logger = new ConsoleLogger();
	}

	public void setPortNumber(int portNumber) {
		this.serverPort = portNumber;
	}
	
	public void stopListening(){
		
	}
	
	public void start() {
		boolean state = getIsThreadRuning();
		if(!state) {
			putIsThreadRuning(true);
			
			try {
				//if(!isServerRunning) {
					isServerRunning = true;
					logger.writeEntry("Create Server Socket");
					logger.writeEntry("Port Number: " + serverPort);
					serverSocket = new ServerSocket(serverPort);
				//}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			new Thread(this).start();
		} 
	}
	
	public void ledInitializeCommand(DataInputStream in) throws IOException {
		final int no    = in.readInt();
		//logger.writeEntry("Received no :" + no);
		final int value = in.readInt();
		//logger.writeEntry("Received value :" + value);
		view.display.asyncExec(new Runnable() {
			public void run() {
				view.initLedPanel(view.viewer, view.ledPanel, no, value);
			}
		});
		
	}
	
	public void ledUpdateCommand(DataInputStream in) throws IOException {
		int no    = in.readInt();
		//logger.writeEntry("Received no :" + no);
		int value = in.readInt();
		//logger.writeEntry("Received value :" + value);
		Led led = new Led(no, value);

		if( no <= view.ledPanel.getList().size()) {
			view.ledPanel.changeTarget(no, led);
			view.display.asyncExec(new Runnable() {
				public void run() {
					view.viewer.setInput(view.ledPanel);
				}
			});
		}
	}
	
	public void decode(DataInputStream   in, DataOutputStream   out) {
		
		while(true) {
			try {
				//logger.writeEntry("Start Received packet");
				short   sizeOfPacket = in.readShort();
				//logger.writeEntry("Received sizeOfPacket :" + sizeOfPacket);
				short   command      = in.readShort();
				//logger.writeEntry("Received command :" + command);
				
				
				switch (command) {
					case LedProtocol.PK_LED_UPDATE : {
						ledUpdateCommand(in);
						break;
					}
					case LedProtocol.PK_LED_INITIALIZE : {
						ledInitializeCommand(in);
						break;
					}
					default : logger.writeEntry("Unknown command :" + command); return;
				}
				
				short endMarker = in.readShort();
				if (endMarker != 0x7FFF) {
					logger.writeEntry("EndMarker is broken. : EndMarker = 0x" + Integer.toHexString((int)endMarker) + " (" + Integer.toString((int)endMarker) + ")");
				}

			} catch (IOException e) {
				// TODO Auto-generated catch block
				try {
					logger.writeEntry("Client Socket is closed");
					clientSocket.close();
				} catch (IOException e1) {
				
				}
				return;
			}
		}
	}

	public void run() {
		// TODO Auto-generated method stub

		if(isServerRunning) {
			
			logger.writeEntry("Waiting for client connection");
			try {
				clientSocket = serverSocket.accept();
				in =  new DataInputStream(new BufferedInputStream(clientSocket.getInputStream()));
				out = new DataOutputStream(new BufferedOutputStream(clientSocket.getOutputStream()));
				//in =  new DataInputStream(clientSocket.getInputStream());
				//out = new DataOutputStream(clientSocket.getOutputStream());
			} catch (IOException e) {
				logger.writeEntry("Connection Error");	
			}
			logger.writeEntry("Handing client at" + clientSocket.getInetAddress().getHostName() + " on port " + clientSocket.getPort());
		}
		if (in != null && out != null) {
			decode(in, out);
		}
		
		try {
			serverSocket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		putIsThreadRuning(false);
		logger.writeEntry("Exit Thread");
	}
}
